package org.infodavid.common.persistence.impl;

import java.sql.Connection;
import java.util.Collection;

import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import javax.sql.XAConnection;
import javax.sql.XADataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.infodavid.common.annotations.AImplementation;
import org.infodavid.common.annotations.AImplementation.ERuntime;
import org.infodavid.common.persistence.ConnectionHelperRegistry;
import org.infodavid.common.persistence.IConnectionConfiguration;
import org.infodavid.common.persistence.IConnectionHelper;
import org.infodavid.common.reflect.InstantiationHelper;

/**
 * The Class ConnectionHelperRegistryImpl.
 */
@AImplementation(runtime = ERuntime.DEFAULT, value = ConnectionHelperRegistry.class)
public final class ConnectionHelperRegistryImpl extends ConnectionHelperRegistry {

	/** The Constant LOGGER. */
	private static final Log LOGGER = LogFactory.getLog(ConnectionHelperRegistryImpl.class);

	/**
	 * The Constructor.
	 * @throws Exception the exception
	 */
	private ConnectionHelperRegistryImpl() throws Exception {
		super();

		final Collection<IConnectionHelper> helpers =
		    InstantiationHelper.getInstance().newInstances(IConnectionHelper.class);

		if (helpers == null || helpers.isEmpty()) {
			LOGGER.warn("No helper defined");
		}
		else {
			LOGGER.info(helpers.size() + " helpers found");

			for (final IConnectionHelper helper : helpers) {
				register(helper);
			}
		}
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#openConnection(com.org.infodavid.common.persistence.IConnectionConfiguration)
	 */
	@Override
	public Connection openConnection(final IConnectionConfiguration conf) throws PersistenceException {
		final IConnectionHelper helper = getEntry(conf.getType());

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + conf.getType());
		}

		return helper.openConnection(conf);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#openDataSource(com.org.infodavid.common.persistence.IConnectionConfiguration)
	 */
	@Override
	public DataSource openDataSource(final IConnectionConfiguration conf) throws PersistenceException {
		final IConnectionHelper helper = getEntry(conf.getType());

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + conf.getType());
		}

		return helper.openDataSource(conf);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#openXaConnection(com.org.infodavid.common.persistence.IConnectionConfiguration)
	 */
	@Override
	public XAConnection openXaConnection(final IConnectionConfiguration conf)
	    throws PersistenceException {
		final IConnectionHelper helper = getEntry(conf.getType());

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + conf.getType());
		}

		return helper.openXaConnection(conf);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#openXaDataSource(com.org.infodavid.common.persistence.IConnectionConfiguration)
	 */
	@Override
	public XADataSource openXaDataSource(final IConnectionConfiguration conf)
	    throws PersistenceException {
		final IConnectionHelper helper = getEntry(conf.getType());

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + conf.getType());
		}

		return helper.openXaDataSource(conf);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#getConnectionString(com.org.infodavid.common.persistence.IConnectionConfiguration)
	 */
	@Override
	public String getConnectionString(final IConnectionConfiguration conf)
	    throws PersistenceException {
		final IConnectionHelper helper = getEntry(conf.getType());

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + conf.getType());
		}

		return helper.getConnectionString(conf);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#createSchema(java.sql.Connection,
	 *      com.org.infodavid.common.persistence.IConnectionConfiguration)
	 */
	@Override
	public void createSchema(final Connection connection, final IConnectionConfiguration conf)
	    throws PersistenceException {
		final IConnectionHelper helper = getEntry(conf.getType());

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + conf.getType());
		}

		helper.createSchema(connection, conf);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#createUser(java.lang.String,
	 *      java.sql.Connection, java.lang.String, java.lang.String)
	 */
	@Override
	public void createUser(final String type, final Connection connection, final String username,
	    final String password) throws PersistenceException {
		final IConnectionHelper helper = getEntry(type);

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + type);
		}

		helper.createUser(connection, username, password);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#deleteUser(java.lang.String,
	 *      java.sql.Connection, java.lang.String)
	 */
	@Override
	public void deleteUser(final String type, final Connection connection, final String username)
	    throws PersistenceException {
		final IConnectionHelper helper = getEntry(type);

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + type);
		}

		helper.deleteUser(connection, username);
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.persistence.ConnectionHelperRegistry#hasSchema(java.lang.String,
	 *      java.sql.Connection, java.lang.String)
	 */
	public boolean hasSchema(final String type, final Connection connection, final String name)
	    throws PersistenceException {
		final IConnectionHelper helper = getEntry(type);

		if (helper == null) {
			throw new PersistenceException("No helper defined for database type: " + type);
		}

		return helper.hasSchema(connection, name);
	}
}
